package com.lyy.system.controller;

import com.alibaba.druid.util.Base64;
import com.lyy.common.constant.Token;
import com.lyy.common.shiro.PswdToken;
import com.lyy.common.utils.*;
import com.lyy.system.pojo.SysImgCode;
import com.lyy.system.pojo.SysUser;
import com.lyy.system.pojo.SysVcode;
import com.lyy.system.service.SysImgCodeService;
import com.lyy.system.service.SysUserService;
import com.lyy.system.service.SysVcodeService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.*;

/**
 * @author 俞伟
 * @version 1.0
 * @date 2020/9/30
 * @description com.lyy.system.controller
 */
@Slf4j
@RestController
@RequestMapping("/login")
public class LoginController {
    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private SysVcodeService sysVcodeService;
    @Autowired
    private SysImgCodeService sysImgCodeService;

    /**
     * /login/userLogin 密码登录
     *
     * @param username
     * @param password
     */
    @PostMapping("/userLogin")
    public Map<String, Object> pswdWebLogin(HttpServletRequest request, String username, String password) {
        if (StringUtils.isBlank(username)) {
            return ResultUtils.getResult(ResultInfo.PARAME_EMPTY, "用户名不能为空");
        }
        if (StringUtils.isBlank(password)) {
            return ResultUtils.getResult(ResultInfo.PARAME_EMPTY, "密码不能为空");
        }
        PswdToken pswdToken = new PswdToken(username, password, "Pswd");
        try {
            SecurityUtils.getSubject().login(pswdToken);
        } catch (UnknownAccountException e) {
            return ResultUtils.getResult(ResultInfo.USER_NOT_EXISTS);
        } catch (IncorrectCredentialsException e) {
            return ResultUtils.getResult(ResultInfo.USER_PASSWORD);
        } catch (LockedAccountException e) {
            return ResultUtils.getResult(ResultInfo.USER_FROZEN);
        }
        SysUser user = sysUserService.getUserByUserName(username);
        Date loginTime = new Date();
        user.setLoginTime(loginTime);
        Token token = sysUserService.getToken(username, user.getPassword());
        sysUserService.updateSysUser(user);
        Map<String, Object> resultData = new HashMap<String, Object>();
        //token
        resultData.put("token", token);
        //用户对象
        resultData.put("user", user);
        log.info("{}::登录成功", username);
        return ResultUtils.getResult(ResultInfo.SUCCESS, null, resultData);
    }

    /**
     * 校验验证码是否正确
     *
     * @param username
     * @param vcode
     * @return
     */
    public void checkVcode(String username, String vcode) {
        // 判断当前用户是否在白名单
        int cnt = sysVcodeService.checkWhitePhone(username);
        if (cnt <= 0) {
            SysVcode code = sysVcodeService.getVcodeById(username);
            if (null != code) {
                long currentTime = System.currentTimeMillis();
                if (currentTime - Long.parseLong(code.getTimeStamp1()) > Constants.TIME_DIFF) {
                    AssertUtils.error("验证码已过期");
                } else if (!code.getVcode().equals(vcode)) {
                    AssertUtils.error("验证码不正确");
                }
            } else {
                AssertUtils.error("请先发送短信验证码");
            }
        }
    }


    /**
     * /login/getSeconds
     * 获取验证码发送秒数
     *
     * @return
     */
    @GetMapping("getSeconds")
    public Result getSeconds() {
        long seconds = Constants.TIME_DIFF / 1000;
        Map<String, Object> map = new HashMap<>();
        map.put("seconds", seconds);
        return Result.getResult(ResultInfo.SUCCESS, map);
    }

    /**
     * /login/sendMsg 发送验证码
     *
     * @param username
     */
    @PostMapping("/sendMsg")
    public Result sendMsg(String username) {
        SysUser temp = sysUserService.getUserByUserName(username);
        AssertUtils.isTrue(null != temp, "用户已存在!");
        AssertUtils.isTrue(StringUtils.isBlank(username), "手机号码不能为空");
        AssertUtils.isFalse(RulesUtils.checkIsMobiles(username), "手机号码格式不正确");
        // 判断当前用户是否在白名单
        int cnt = sysVcodeService.checkWhitePhone(username);
        if (cnt <= 0) {
            // 获取短信验证码
            String vcode = sysVcodeService.getPhoneCode(username);
            AssertUtils.isTrue("0".equals(vcode), "手机验证码发送失败");
            long minutes = Constants.TIME_DIFF / 60 / 1000;
            AssertUtils.isTrue("3".equals(vcode), "每次获取动态密码的时间间隔不能小于" + minutes + "分钟");
            AssertUtils.isTrue("5".equals(vcode), "每小时获取动态验证码不能超过5次");
            AssertUtils.isTrue("20".equals(vcode), "每天获取动态验证码不能超过20次");
        }
        return Result.getResult(ResultInfo.SUCCESS);
    }


    /**
     * 注册用户
     * login/register
     *
     * @param user
     * @return
     */
    @PostMapping("/register")
    public Map<String, Object> register(SysUser user) {
        if (StringUtils.isBlank(user.getUsername())) {
            return ResultUtils.getResult(ResultInfo.PARAME_EMPTY, "用户名不能为空");
        }
        AssertUtils.isFalse(RulesUtils.checkIsMobiles(user.getUsername()), "手机号码格式不正确");
        if (StringUtils.isBlank(user.getPassword())) {
            return ResultUtils.getResult(ResultInfo.PARAME_EMPTY, "密码不能为空");
        }
        checkVcode(user.getUsername(), user.getVcode());
        SysUser temp = sysUserService.getUserByUserName(user.getUsername());
        AssertUtils.isTrue(null != temp, "账号已存在");
        user.setName(user.getUsername());
        user.setSalt(DigestUtils.md5Hex(UUID.randomUUID().toString() + System.currentTimeMillis() + UUID.randomUUID().toString()));
        user.setPassword(sysUserService.passwordEncoder(user.getPassword(), user.getSalt()));
        sysUserService.createSysUser(user);
        return ResultUtils.getResult(ResultInfo.SUCCESS);
    }


    /**
     * 检测用户名是否已经存在
     * login/getUserByUserName
     *
     * @param username 用户名称
     * @return
     */
    @GetMapping("/getUserByUserName")
    public Result getUserByUserName(String username) {
        AssertUtils.isFalse(RulesUtils.checkIsMobiles(username), "手机号码格式不正确");
        SysUser temp = sysUserService.getUserByUserName(username);
        AssertUtils.isTrue(null != temp, "用户已存在!");
        return Result.getResult(ResultInfo.SUCCESS);
    }

    /**
     * /login/getCaptchaCode 获取图片验证码
     */
    @GetMapping("/getCaptchaCode")
    public Result getCaptchaCode(HttpServletRequest request, HttpServletResponse response, String identifying) {
        SysImgCode params = new SysImgCode();
        params.setId(identifying);
        sysImgCodeService.deleteSysImgCode(params);
        response.addHeader("P3P", "CP=CAO PSA OUR");
        response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
        response.setHeader("Access-Control-Allow-Methods", "PUT,GET,POST,DELETE,OPTIONS");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        try {
            ValidateCode validateCode = new ValidateCode();
            // 获取验证码图片
            BufferedImage image = validateCode.getImage();
            // 获取验证码内容
            String text = validateCode.getText();
            // 禁止图像缓存。
            response.setHeader("Pragma", "no-cache");
            response.setHeader("Cache-Control", "no-cache");
            response.setDateHeader("Expires", 0);
            response.setContentType("image/jpeg");
            ByteArrayOutputStream sos = null;
            String imgsrc = "";
            try {
                sos = new ByteArrayOutputStream();
                ImageIO.write(image, "jpeg", sos);
                imgsrc = Base64.byteArrayToBase64(sos.toByteArray());
                SysImgCode sysImgCode = new SysImgCode();
                sysImgCode.setCreateDate(new Date());
                sysImgCode.setVcode(text);
                sysImgCodeService.createSysImgCode(sysImgCode);
                Map<String, Object> resultData = new HashMap<String, Object>();
                resultData.put("imgsrc", imgsrc);
                resultData.put("identifying", sysImgCode.getId());
                return Result.getResult(ResultInfo.SUCCESS, resultData);
            } catch (Exception e) {
                log.error(e.toString(), e);
            } finally {
                if (null != sos) {
                    sos.flush();
                    sos.close();
                }
            }
        } catch (Exception e) {
            log.error(e.toString(), e);
        }
        return Result.getResult(ResultInfo.FAILED);
    }

    /**
     * /login/checkCaptchaCode校验图片验证码
     *
     * @param captcha     你输入的数字
     * @param identifying 识别码
     */
    @PostMapping("/checkCaptchaCode")
    public Map<String, Object> checkCaptchaCode(String captcha, String identifying) {
        AssertUtils.notNull(captcha, "请输入验证码");
        AssertUtils.notNull(identifying, "识别码不能为空");
        SysImgCode params = new SysImgCode();
        params.setId(identifying);
        SysImgCode sysImgCode = sysImgCodeService.getSysImgCode(params);
        AssertUtils.notNull(sysImgCode, "验证码错误");
        String signcodeSession = sysImgCode.getVcode();
        log.info("signcode==>" + captcha);
        log.info("signcodeSession==>" + signcodeSession);
        // 验证的时候不区分大小写
        AssertUtils.isFalse(captcha.equalsIgnoreCase(signcodeSession), "验证码错误");
        sysImgCodeService.deleteSysImgCode(params);
        return ResultUtils.getResult(ResultInfo.SUCCESS);
    }
}
